package soar.test.qrcode;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.InputStream;
import java.util.Date;
import java.util.HashMap;

import javax.imageio.ImageIO;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;

class Conf
{
    public static final int image_width = 480;
    public static final int image_width_margin = 30;
    public static final int image_height = 480;
    public static final int image_height_margin = 30;
}

public class App
{
    private final static String __CLASS__ = App.class.getName();

    public static void main(String[] args)
    {
        final String __METHOD__ = "main";

        if (args.length < 1)
        {
            System.err.println(String.format(
                    "%s.%s: args error", __CLASS__,
                    __METHOD__));
            return;
        }
        String content = args[0];

        new App().run(content);
    }

    private int run(String content)
    {
        final String __METHOD__ = "run";

        System.out.println(new Date() + " -- begin");

        try
        {
            MultiFormatWriter writer = new MultiFormatWriter();
            HashMap<EncodeHintType, Object> hint = new HashMap<>();
            hint.put(EncodeHintType.CHARACTER_SET, "utf-8");
            hint.put(EncodeHintType.ERROR_CORRECTION,
                    ErrorCorrectionLevel.H);

            BufferedImage logo = get_logo("picture.jpg");

            int[] pixels = gencode(writer, hint, content);

            // 合并
            int width = Conf.image_width - Conf.image_width_margin * 2;
            int height = Conf.image_height - Conf.image_height_margin * 2;
            BufferedImage img = new BufferedImage(width, height,
                    BufferedImage.TYPE_INT_RGB);
            img.getRaster().setDataElements(0, 0, img.getWidth(),
                    img.getHeight(), pixels);
            Graphics2D g2d = img.createGraphics();
            g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
                    RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
            g2d.drawImage(logo, img.getWidth() / 2 - logo.getWidth() / 2,
                    img.getHeight() / 2 - logo.getHeight() / 2, null);
            g2d.dispose();

            ImageIO.write(img, "jpg", new File("qrcode.jpg"));
        }
        catch (Exception e)
        {
            System.out.println(String.format("%s.%s: fail, %s", __CLASS__,
                    __METHOD__, e));
            return 1;
        }

        System.out.println(new Date() + " -- end");

        return 0;
    }

    private BufferedImage get_logo(String name) throws Exception
    {
        InputStream is = this.getClass().getResourceAsStream("/" + name);
        BufferedImage img = ImageIO.read(is);
        is.close();

        double ratio = 0.15;
        int width = (int) (img.getWidth() * ratio);
        int height = (int) (img.getHeight() * ratio);
        BufferedImage new_img = new BufferedImage(width, height,
                BufferedImage.TYPE_3BYTE_BGR);
        Graphics2D g = new_img.createGraphics();
        new_img = g.getDeviceConfiguration().createCompatibleImage(width,
                height, Transparency.TRANSLUCENT);
        g.dispose();
        g = new_img.createGraphics();
        g.drawImage(
                img.getScaledInstance(width, height, Image.SCALE_SMOOTH),
                0, 0, null);
        g.dispose();

        ratio = 0.17;
        int merge_width = (int) (img.getWidth() * ratio);
        int merge_height = (int) (img.getHeight() * ratio);
        BufferedImage merge = new BufferedImage(merge_width, merge_height,
                BufferedImage.TYPE_3BYTE_BGR);
        g = merge.createGraphics();
        g.setBackground(Color.WHITE);
        g.clearRect(0, 0, merge_width, merge_height);
        g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
                RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
        g.drawImage(new_img,
                merge.getWidth() / 2 - new_img.getWidth() / 2,
                merge.getHeight() / 2 - new_img.getHeight() / 2, null);

        return merge;
    }

    private int[] gencode(MultiFormatWriter writer,
            HashMap<EncodeHintType, Object> hint, String content)
            throws Exception
    {
        BitMatrix matrix = writer.encode(content, BarcodeFormat.QR_CODE,
                Conf.image_width, Conf.image_height, hint);
        int width = Conf.image_width - Conf.image_width_margin * 2;
        int height = Conf.image_height - Conf.image_height_margin * 2;
        int[] pixels = new int[width * height];
        for (int y = 0; y < height; ++y)
        {
            for (int x = 0; x < width; ++x)
            {
                Color color = matrix.get(x + Conf.image_width_margin, y
                        + Conf.image_height_margin) ? Color.BLACK
                        : Color.WHITE;
                pixels[x + y * width] = color.getRGB();
            }
        }

        return pixels;
    }
}
